/*##########################################################################

	userpane.cp

	Copyright (c) 2001-5 Aspyr Media Interactive. All Rights Reserved.

##########################################################################*/

Q3DEF_BEGIN
#include "../../client/client.h"
#include "../mac_local.h"
Q3DEF_END

#define MacWarning Sys_Warning
#define MacFatalError Sys_Error

#include "userpane.h"


/*##########################################################################
	TYPES
##########################################################################*/
struct PaneData
{
	ControlUserPaneDrawUPP drawUPP;
	ControlUserPaneHitTestUPP hitTestUPP;
	ControlUserPaneTrackingUPP trackingUPP; 
	ControlUserPaneIdleUPP idleUPP; 
	ControlUserPaneKeyDownUPP keyDownUPP;
	ControlUserPaneActivateUPP activateUPP; 
	ControlUserPaneFocusUPP focusUPP; 
	ControlUserPaneBackgroundUPP backgroundUPP;
	ControlRef paneControl;
	struct PaneData **nextPane;
};
typedef struct PaneData PaneData;
typedef PaneData *PaneDataPtr;
typedef PaneDataPtr *PaneDataHandle;


/*##########################################################################
	GLOBALS
##########################################################################*/
static PaneDataHandle sRootPane;	// linked list head

#pragma require_prototypes on


/*##########################################################################
	IMPLEMENTATION
##########################################################################*/

//===============================================================================
//	AddPaneDataToList
//
// 	Add the specified PaneDataHandle to the linked list.
//===============================================================================

static void AddPaneDataToList(PaneDataHandle inPaneData)
{
	if (sRootPane)
		(**inPaneData).nextPane = sRootPane;

	sRootPane = inPaneData;
}


//===============================================================================
//	RemovePaneDataFromList
//
// 	Remove the specified PaneDataHandle from the linked list.
//===============================================================================

static void RemovePaneDataFromList(PaneDataHandle inPaneData)
{
	if (sRootPane == inPaneData)
	{
		sRootPane = (**sRootPane).nextPane;
	}
	else
	{
		PaneDataHandle pane = sRootPane;
		
		while (pane)
		{
			if ((**pane).nextPane == inPaneData)
			{
				(**pane).nextPane = (**inPaneData).nextPane;
				break;
			}
			pane = (**pane).nextPane;
		}
	}
}


//===============================================================================
//	GetPaneDataByControl
//
// 	Retrieve the appropriate PaneDataHandle for the specified control.
//===============================================================================

static PaneDataHandle GetPaneDataByControl(ControlRef inControl)
{
	if (0 == inControl) return 0;
	
	PaneDataHandle pane = sRootPane;
	
	while(pane)
	{
		if ((**pane).paneControl == inControl)
			break;
		pane = (**pane).nextPane;
	}
	return pane;
}


#pragma mark -


//===============================================================================
//	SetupUserPaneProcs
//
// 	Call this to initialize the specified user pane control before displaying 
//	the dialog window. Pass NULL for any user pane procs you don't need to install.
//===============================================================================

OSErr SetupUserPaneProcs(	ControlRef inUserPane,
							ControlUserPaneDrawProcPtr inDrawProc, 
							ControlUserPaneHitTestProcPtr inHitTestProc,
							ControlUserPaneTrackingProcPtr inTrackingProc, 
							ControlUserPaneIdleProcPtr inIdleProc, 
							ControlUserPaneKeyDownProcPtr inKeyDownProc,
							ControlUserPaneActivateProcPtr inActivateProc, 
							ControlUserPaneFocusProcPtr inFocusProc, 
							ControlUserPaneBackgroundProcPtr inBackgroundProc)
{
	OSErr	err;
	
	if (0 == inUserPane) return paramErr;
	if (GetPaneDataByControl(inUserPane) != 0) return paramErr;
	
	PaneDataHandle pane = (PaneDataHandle)NewHandleClear(sizeof(PaneData));
	err = MemError();
	if (pane == 0)
		return (err ? err : memFullErr);
	HLock((Handle)pane);

	if (inDrawProc && noErr == err)
	{
		(**pane).drawUPP = NewControlUserPaneDrawUPP(inDrawProc);

		if (0 == (**pane).drawUPP)
			err = memFullErr;
		else
			err = SetControlData(	inUserPane,
									kControlEntireControl,
									kControlUserPaneDrawProcTag,
									sizeof(ControlUserPaneDrawUPP),
									(Ptr)&(**pane).drawUPP);
	}
	if (inHitTestProc && noErr == err)
	{
		(**pane).hitTestUPP = NewControlUserPaneHitTestUPP(inHitTestProc);

		if (0 == (**pane).hitTestUPP)
			err = memFullErr;
		else
			err = SetControlData(	inUserPane,
									kControlEntireControl, 
									kControlUserPaneHitTestProcTag,
									sizeof(ControlUserPaneHitTestUPP),
									(Ptr)&(**pane).hitTestUPP);
	}
	if (inTrackingProc && noErr == err)
	{
		(**pane).trackingUPP = NewControlUserPaneTrackingUPP(inTrackingProc);
		
		if (0 == (**pane).trackingUPP)
			err = memFullErr;
		else
			err = SetControlData(	inUserPane,
									kControlEntireControl, 
									kControlUserPaneTrackingProcTag,
									sizeof(ControlUserPaneTrackingUPP),
									(Ptr)&(**pane).trackingUPP);
	}
	if (inIdleProc && noErr == err)
	{
		(**pane).idleUPP = NewControlUserPaneIdleUPP(inIdleProc);
		
		if (0 == (**pane).idleUPP)
			err = memFullErr;
		else
			err = SetControlData(	inUserPane, 
									kControlEntireControl,
									kControlUserPaneIdleProcTag,
									sizeof(ControlUserPaneIdleUPP),
									(Ptr)&(**pane).idleUPP);
	}
	if (inKeyDownProc && noErr == err)
	{
		(**pane).keyDownUPP = NewControlUserPaneKeyDownUPP(inKeyDownProc);
		if (0 == (**pane).keyDownUPP)
			err = memFullErr;
		else
			err = SetControlData(	inUserPane,
									kControlEntireControl, 
									kControlUserPaneKeyDownProcTag,
									sizeof(ControlUserPaneKeyDownUPP),
									(Ptr)&(**pane).keyDownUPP);
	}
	if (inActivateProc && noErr == err)
	{
		(**pane).activateUPP = NewControlUserPaneActivateUPP(inActivateProc);
		if (0 == (**pane).activateUPP)
			err = memFullErr;
		else
			err = SetControlData(	inUserPane,
									kControlEntireControl, 
									kControlUserPaneActivateProcTag,
									sizeof(ControlUserPaneActivateUPP),
									(Ptr)&(**pane).activateUPP);
	}
	if (inFocusProc && noErr == err)
	{
		(**pane).focusUPP = NewControlUserPaneFocusUPP(inFocusProc);
		if (0 == (**pane).focusUPP)
			err = memFullErr;
		else
			err = SetControlData(	inUserPane,
									kControlEntireControl, 
									kControlUserPaneFocusProcTag,
									sizeof(ControlUserPaneFocusUPP),
									(Ptr)&(**pane).focusUPP);
	}
	if (inBackgroundProc && noErr == err)
	{
		(**pane).backgroundUPP = NewControlUserPaneBackgroundUPP(inBackgroundProc);
		if (0 == (**pane).backgroundUPP)
			err = memFullErr;
		else
			err = SetControlData(	inUserPane,
									kControlEntireControl, 
									kControlUserPaneBackgroundProcTag,
									sizeof(ControlUserPaneBackgroundUPP),
									(Ptr)&(**pane).backgroundUPP);
	}
	
	if (noErr == err)
	{	
		HUnlock((Handle)pane);
		AddPaneDataToList(pane);
		(**pane).paneControl = inUserPane;
	}
	else
	{
		if (pane)
			DisposeHandle((Handle)pane);
	}
	
	return err;
}


//===============================================================================
//	DisposeUserPaneProcs
//
// 	Call this to clean up when you're done with the specified user pane control.
//===============================================================================

OSErr DisposeUserPaneProcs(ControlRef inUserPane)
{
	PaneDataHandle pane = GetPaneDataByControl(inUserPane);
	if (0 == pane)
		return paramErr;
	
	RemovePaneDataFromList(pane);
	
	if ((**pane).drawUPP) DisposeControlUserPaneDrawUPP((**pane).drawUPP);
	if ((**pane).trackingUPP) DisposeControlUserPaneTrackingUPP((**pane).trackingUPP);
	if ((**pane).idleUPP) DisposeControlUserPaneIdleUPP((**pane).idleUPP);
	if ((**pane).keyDownUPP) DisposeControlUserPaneKeyDownUPP((**pane).keyDownUPP);
	if ((**pane).activateUPP) DisposeControlUserPaneActivateUPP((**pane).activateUPP);
	if ((**pane).focusUPP) DisposeControlUserPaneFocusUPP((**pane).focusUPP);
	if ((**pane).backgroundUPP) DisposeControlUserPaneBackgroundUPP((**pane).backgroundUPP);

	DisposeHandle((Handle)pane);
	return noErr;
}
